/*
 * Copyright 2024 The JA-SIG Collaborative. All rights reserved.
 * distributed with thi file and available online at
 */
package com.lap.permission.service.impl;

import com.lap.permission.cachekey.ResourceKey;
import com.lap.permission.dal.ResourceDAO;
import com.lap.permission.dal.UserRoleDAO;
import com.lap.permission.domain.entity.Resource;
import com.lap.permission.manager.ResourceManager;
import com.lap.permission.service.ResourceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Slf4j
@RequiredArgsConstructor
@Service
public class ResourceServiceImpl implements ResourceService {

    private final ResourceManager resourceManager;

    private final ResourceDAO resourceDAO;

    private final UserRoleDAO userRoleDAO;

    @Cacheable(value = ResourceKey.RESOURCE_TREE, unless = "#result.isEmpty()")
    @Override
    public List<Resource> queryTree() {
        List<Resource> sources = resourceDAO.queryList();

        if (CollectionUtils.isEmpty(sources))
            return Collections.emptyList();

        List<Resource> result = sources.stream()
                .filter(e -> StringUtils.isBlank(e.getParentCode()))
                .toList();

        int dept = 0;
        for (Resource resource : result) {
            getResource(sources, resource, dept);
        }
        return result;
    }

    /**
     * 递归方式获取资源树,防止垃圾数据导致栈溢出
     *
     * @param parent  父资源对象
     * @param sources 资源信息
     * @param dept    递归深度
     */
    private Resource getResource(List<Resource> sources, Resource parent, int dept) {
        log.debug("dept:::{}", dept);
        ++dept;
        if (dept >= 30)
            return parent;

        for (Resource resource : sources) {
            if (parent.getCode().equals(resource.getParentCode())) {
                List<Resource> child = parent.getChildren();
                if (Objects.isNull(child)) {
                    child = new ArrayList<>(sources.size());
                    parent.setChildren(child);
                }
                parent.getChildren().add(getResource(sources, resource, dept));
            }
        }
        return parent;
    }

    @Override
    public Resource queryById(Integer resourceId) {
        return resourceDAO.queryById(resourceId);
    }

    @Override
    public List<Resource> queryByModule(String module) {
        return resourceDAO.queryByModule(module);
    }

    @Cacheable(value = ResourceKey.RESOURCE_USER, key = "#userId", unless = "#result == null")
    @Override
    public List<Resource> queryByUserId(Integer userId) {
        List<Integer> roleIds = userRoleDAO.queryByUserId(userId);
        if (CollectionUtils.isEmpty(roleIds))
            return Collections.emptyList();

        return resourceDAO.queryByRoleIds(roleIds);
    }

    @Override
    public List<Resource> queryByService(Integer type) {
        return resourceDAO.queryByService(type);
    }

    @Override
    public List<Resource> queryByMenuId(Integer menuId) {
        return resourceDAO.queryByMenuId(menuId);
    }

    @CacheEvict(value = {ResourceKey.RESOURCE_USER, ResourceKey.RESOURCE_TREE}, allEntries = true)
    @Override
    public Integer insertResourceBatch(String module, List<Resource> resources) {
        return resourceManager.insertResourceBatch(module, resources);
    }

    @CacheEvict(value = {ResourceKey.RESOURCE_USER, ResourceKey.RESOURCE_TREE}, allEntries = true)
    @Override
    public int updateResource(Resource resource) {
        return resourceDAO.updateResource(resource);
    }

}
